package main

import (
	"database/sql"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"time"
	_ "github.com/go-sql-driver/mysql"
)

//数据库连接信息
const (
	USERNAME = "root"
	PASSWORD = "123456"
	NETWORK = "tcp"
	SERVER = "127.0.0.1"
	PORT = 3306
	DATABASE = "test"
)

//user表结构体定义
type User struct {
	Id int `json:"id" form:"id"`
	Username string `json:"username" form:"username"`
	Password string `json:"password" form:"password"`
}

//查询单行
func QueryOne(DB *sql.DB,queriedUserName string) {
	user := new(User)   //用new()函数初始化一个结构体对象
	row := DB.QueryRow("select id,username,password from users where username=?",queriedUserName)
	//row.scan中的字段必须是按照数据库存入字段的顺序，否则报错
	if err := row.Scan(&user.Id,&user.Username,&user.Password); err != nil {
		fmt.Printf("scan failed, err:%v\n", err)
		return
	}
	fmt.Println("Single row data:", *user)
}

// 登陆页面
func loginHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("%s 请求一个登录页面\n",r.RemoteAddr)
	// 如果是post请求，注意先后顺序
	if r.Method == http.MethodPost {
		// 解析表单 并且校验
		err := r.ParseForm()
		if err != nil {
			log.Printf("function ParseForm error: %s\n",err.Error())
		}
		userName := r.FormValue("username")
		pwd := r.FormValue("password")

		// 如果输入正确，则发送cookie 并给出反馈
		if userName == "zhangsan" && pwd == "123456" {

			c1 := &http.Cookie{
				Name:     "username",
				Value:    userName,
				MaxAge:   0,
				HttpOnly: false,
			}

			http.SetCookie(w, c1)

			http.Redirect(w,r,"/main", http.StatusFound)
		} else {
			numOfBytesWritten, err := fmt.Fprint(w, "登陆失败")
			if err != nil {
				log.Printf("function Fprint error: %s\n",err.Error())
			}
			log.Printf("服务器写入%d字节到套接字\n",numOfBytesWritten)
		}
	} else { // 显示登录页面
		// 解析模板
		t, err := template.ParseFiles("login.html")
		if err != nil {
			log.Fatal(err)
		}

		// 准备好参数
		now := time.Now().Format("2006/01/02 15:04:05")
		data := map[string]interface{}{
			"now":   now,
		}

		// 渲染模板
		err = t.Execute(w, data)
		if err != nil {
			log.Printf("function Execute error: %s\n",err.Error())
		}
	}
}

// 拿到cookie，并且显示出来,说明登陆成功
func userInfoHandler(w http.ResponseWriter, r *http.Request) {
	username, err := r.Cookie("username")
	if err != nil {
		numOfBytesWritten, err := fmt.Fprint(w, "未登录")
		if err != nil {
			log.Printf("function Fprint error: %s\n",err.Error())
		}
		log.Printf("服务器写入%d字节到套接字\n",numOfBytesWritten)
		return
	}

	t, err := template.ParseFiles("user_info.html")
	if err != nil {
		log.Fatal(err)
	}

	t.Execute(w, username.Value)
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w,r,"/login", http.StatusFound)
}

//主页面
func mainContentHandler(w http.ResponseWriter, r *http.Request) {
	//检测cookie
	_, err := r.Cookie("username")
	if err != nil {
		http.Redirect(w,r,"/login", http.StatusFound)
	}

	//发送主页面
	t, err := template.ParseFiles("homework_1/电信1902程儒U201913535.html")
	if err != nil {
		log.Fatal(err)
	}
	t.Execute(w, nil) //第二个参数表示向模版传递的数据
}

//注销
func logoutHandler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w,r,"/login", http.StatusFound)
}

func queryHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost {
		// 解析表单 获取需要查询的姓名
		err := r.ParseForm()
		if err != nil {
			log.Printf("function ParseForm error: %s\n",err.Error())
		}
		userName := r.FormValue("queriedUser")

		// 在数据库中查询
		conn := fmt.Sprintf("%s:%s@%s(%s:%d)/%s",USERNAME, PASSWORD, NETWORK, SERVER, PORT, DATABASE)
		DB, err := sql.Open("mysql", conn)
		if err != nil {
			log.Printf("connection to mysql failed: %s\n", err.Error())
		}
		user := new(User)   //用new()函数初始化一个结构体对象
		row := DB.QueryRow("select id,username,password from users where username=?",userName)
		//row.scan中的字段必须是按照数据库存入字段的顺序，否则报错
		if err := row.Scan(&user.Id,&user.Username,&user.Password); err != nil {
			user.Id=-1
			user.Username="NO_RESULT"
			user.Password="NO_RESULT"
			log.Printf(err.Error()+"\n")
		}
		// 解析模板
		t, err := template.ParseFiles("query_result.html")
		if err != nil {
			log.Fatal(err)
		}

		// 准备好参数
		data := map[string]interface{}{
			"id":   &user.Id,
			"username":   &user.Username,
			"password":   &user.Password,
		}

		// 渲染模板
		err = t.Execute(w, data)
		if err != nil {
			log.Printf("function Execute error: %s\n",err.Error())
		}
	}
}

func main() {

	mux := http.NewServeMux()
	mux.HandleFunc("/", indexHandler)
	mux.HandleFunc("/login", loginHandler)
	mux.HandleFunc("/main", mainContentHandler)
	mux.HandleFunc("/logout", logoutHandler)
	mux.HandleFunc("/query", queryHandler)

	server := &http.Server{
		Addr:    ":8700",   //要登录页面，需要在localhost:8700后面加上/login或者/userinfo才能访问
		Handler: mux,
	}
	fmt.Println("服务器开启...")
	err := server.ListenAndServe()
	if err != nil {
		log.Fatal(err)
	}
}